#ifndef VISITOR_HPP
#define VISITOR_HPP

class Node;
  class ListNode;
   class StmtsNode;
   class ArgsNode;
  class PrintNode;
  class ReturnNode;
  class BinaryOp;
    class CmpNode;
  class LogicNotNode;
  class ConstInt;
  class ConstDouble;
  class ConstString;
  class ConstArray;
  class ImportNode;
  class ImplementNode;
  class TraitDefNode;
  class IfNode;
  class WhileNode;
  class AssignNode;
  class VarNode;
  class VarDefNode;
  class ParamDefNode;
  class FuncDefNode;
  class RecordDefNode;
  class LambdaDef;
  class CallNode;
  class SubscrNode;
  class DotNode;
  class SequenceNode;
  class BuiltinConst;
  class TupleNode;
  class ArrowTypeNode;
  class ArrayTypeNode;

  class TypeVarNode;
  class TypeFuncDefNode;
  class TypeVarDefNode;
  class TypeCallNode;
  class TypeConstInt;
  class TypeTupleNode;
class Visitor {
public:
    virtual Node* visit(Node* n) = 0;

    virtual Node* visit(PrintNode* n) = 0;
    virtual Node* visit(ReturnNode* n) = 0;
    virtual Node* visit(BinaryOp* n) = 0;
    virtual Node* visit(LogicNotNode* n) = 0;
    virtual Node* visit(ListNode* n) = 0;
    virtual Node* visit(StmtsNode* n) = 0;
    virtual Node* visit(ConstInt* n) = 0;
    virtual Node* visit(ConstDouble* n) = 0;
    virtual Node* visit(ConstString* n) = 0;
    virtual Node* visit(ConstArray* n) = 0;
    virtual Node* visit(ImportNode* n) = 0;
    virtual Node* visit(ImplementNode* n) = 0;
    virtual Node* visit(TraitDefNode* n) = 0;
    virtual Node* visit(IfNode* n) = 0;
    virtual Node* visit(WhileNode* n) = 0;
    virtual Node* visit(CmpNode* n) = 0;
    virtual Node* visit(AssignNode* n) = 0;
    virtual Node* visit(VarNode* n) = 0;
    virtual Node* visit(VarDefNode* n) = 0;
    virtual Node* visit(ParamDefNode* n) = 0;
    virtual Node* visit(FuncDefNode* n) = 0;
    virtual Node* visit(RecordDefNode* n) = 0;
    virtual Node* visit(LambdaDef* n) = 0;
    virtual Node* visit(CallNode* n) = 0;
    virtual Node* visit(SubscrNode* n) = 0;
    virtual Node* visit(DotNode* n) = 0;
    virtual Node* visit(SequenceNode* n) = 0;
    virtual Node* visit(BuiltinConst* n) = 0;
    virtual Node* visit(TupleNode* n) = 0;
    virtual Node* visit(ArrowTypeNode* n) = 0;
    virtual Node* visit(ArrayTypeNode* n) = 0;

    virtual Node* visit(TypeVarNode* n) = 0;
    virtual Node* visit(TypeFuncDefNode* n) = 0;
    virtual Node* visit(TypeVarDefNode* n) = 0;
    virtual Node* visit(TypeCallNode* n) = 0;
    virtual Node* visit(TypeConstInt* n) = 0;
    virtual Node* visit(TypeTupleNode* n) = 0;
};

class Dumper : public Visitor {
private:
    int _indent;
    inline void print_indent();
public:
    Dumper() : _indent(0) {}

    Node* visit(Node* n);

    virtual Node* visit(PrintNode* n);
    virtual Node* visit(ReturnNode* n);
    virtual Node* visit(BinaryOp* n);
    virtual Node* visit(LogicNotNode* n);
    virtual Node* visit(ListNode* n);
    virtual Node* visit(StmtsNode* n);
    virtual Node* visit(ConstInt* n);
    virtual Node* visit(ConstDouble* n);
    virtual Node* visit(ConstString* n);
    virtual Node* visit(ConstArray* n);
    virtual Node* visit(ImportNode* n);
    virtual Node* visit(ImplementNode* n);
    virtual Node* visit(IfNode* n);
    virtual Node* visit(WhileNode* n);
    virtual Node* visit(CmpNode* n);
    virtual Node* visit(AssignNode* n);
    virtual Node* visit(VarNode* n);
    virtual Node* visit(VarDefNode* n);
    virtual Node* visit(ParamDefNode* n);
    virtual Node* visit(FuncDefNode* n);
    virtual Node* visit(RecordDefNode* n);
    virtual Node* visit(TraitDefNode* n);
    virtual Node* visit(LambdaDef* n);
    virtual Node* visit(CallNode* n);
    virtual Node* visit(SubscrNode* n);
    virtual Node* visit(DotNode* n);
    virtual Node* visit(SequenceNode* n);
    virtual Node* visit(BuiltinConst* n);
    virtual Node* visit(TupleNode* n);
    // 下面这些也要改成 virtual Node* 返回类型
    virtual Node* visit(ArrowTypeNode* n);
    virtual Node* visit(ArrayTypeNode* n);
    virtual Node* visit(TypeVarNode* n);
    virtual Node* visit(TypeFuncDefNode* n);
    virtual Node* visit(TypeVarDefNode* n);
    virtual Node* visit(TypeCallNode* n);
    virtual Node* visit(TypeConstInt* n);
    virtual Node* visit(TypeTupleNode* n);
};

#endif
